#include <new>

namespace tb
{

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>::List()
	{
		m_Memory = m_Pool;
		m_Maximum = Size;
		m_Offset = 0;
	}

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>::~List()
	{
		Clear();
	}

	template <typename T, unsigned int Size>
	TB_INLINE T& List<T, Size>::operator [] (unsigned int a_Index)
	{
		/*if (a_Index >= m_Maximum)
		{
			unsigned int newmax = m_Maximum * 2;
			//while (a_Index >= newmax) { newmax *= 2; }
			_Resize(newmax);
		}*/

		return m_Memory[a_Index];
	}

	template <typename T, unsigned int Size>
	TB_INLINE const T& List<T, Size>::operator [] (unsigned int a_Index) const
	{
		/*if (a_Index >= m_Maximum)
		{
			unsigned int newmax = m_Maximum * 2;
			//while (a_Index >= newmax) { newmax *= 2; }
			_Resize(newmax);
		}*/

		return m_Memory[a_Index];
	}


	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>& List<T, Size>::Empty()
	{
		m_Offset = 0;

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE bool List<T, Size>::CheckEmpty() const
	{
		return (m_Offset == 0);
	}

	template <typename T, unsigned int Size>
	List<T, Size>& List<T, Size>::Clear()
	{
		if (m_Memory != m_Pool) { delete [] m_Memory; }

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>& List<T, Size>::Reserve(unsigned int a_Count)
	{
		if (a_Count <= m_Maximum) { return *this; }

		_Resize(a_Count);

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>& List<T, Size>::Guarantee(unsigned int a_Count)
	{
		unsigned int newcount = m_Offset + a_Count;
		if (newcount >= m_Maximum)
		{
			unsigned int newmax = (m_Maximum > 0) ? (m_Maximum * 2) : a_Count;
			while (newcount >= newmax) { newmax *= 2; }
			_Resize(newmax);
		}

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>& List<T, Size>::Push(const T& a_Element)
	{
		if (m_Offset >= m_Maximum)
		{
			unsigned int newmax = (m_Maximum > 0) ? (m_Maximum * 2) : 1;
			_Resize(newmax);
		}

		m_Memory[m_Offset] = a_Element;
		m_Offset++;

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE T& List<T, Size>::Pop()
	{
		if (m_Offset > 0) { m_Offset--; }

		return m_Memory[m_Offset];
	}

	template <typename T, unsigned int Size>
	TB_INLINE T& List<T, Size>::GetTop()
	{
		return m_Memory[m_Offset];
	}

	template <typename T, unsigned int Size>
	TB_INLINE const T& List<T, Size>::GetTop() const
	{
		return m_Memory[m_Offset];
	}

	template <typename T, unsigned int Size>
	TB_INLINE T& List<T, Size>::GetBottom()
	{
		return m_Memory[m_Offset];
	}

	template <typename T, unsigned int Size>
	TB_INLINE const T& List<T, Size>::GetBottom() const
	{
		return m_Memory[m_Offset];
	}

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>& List<T, Size>::Next()
	{
		if (m_Offset + 1 < m_Maximum)
		{
			m_Offset++;
		}

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE List<T, Size>& List<T, Size>::Previous()
	{
		if (m_Offset - 1 > 0 && m_Offset - 1 < m_Maximum)
		{
			m_Offset--;
		}

		return *this;
	}

	template <typename T, unsigned int Size>
	TB_INLINE void List<T, Size>::_Resize(unsigned int a_Count)
	{
		T* newmem = new T[a_Count];
		for (unsigned int i = 0; i < m_Maximum; i++) { newmem[i] = m_Memory[i]; }
		if (m_Memory != m_Pool) { delete [] m_Memory; }
		m_Memory = newmem;
		m_Maximum = a_Count;
	}

	template <typename T, unsigned int Size>
	TB_INLINE unsigned int List<T, Size>::GetSize() const
	{
		return m_Offset;
	}

	template <typename T, unsigned int Size>
	TB_INLINE unsigned int List<T, Size>::GetMaximum() const
	{
		return m_Maximum;
	}

}; // namespace tb